package com.feemanage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.common.api.ApprovalApi;
import com.common.core.domain.entity.SysUser;
import com.common.core.page.PageDomain;
import com.common.utils.CurrentRoleUtils;
import com.common.utils.SecurityUtils;
import com.common.utils.bean.BizProcessMessages;
import com.common.utils.sql.SqlUtil;
import com.feemanage.common.SearchUtils;
import com.feemanage.domain.BizProjectPayout;
import com.feemanage.domain.BizProjectPayoutDetail;
import com.feemanage.domain.BudgetSubjectPayout;
import com.feemanage.domain.bo.PayoutDetailsBo;
import com.feemanage.domain.bo.ProjectPayoutBo;
import com.feemanage.domain.vo.BizProjectPayoutVo;
import com.feemanage.domain.vo.ProjectPayoutVo;
import com.feemanage.mapper.bizProjectPayoutDetailMapper;
import com.feemanage.mapper.bizProjectPayoutMapper;
import com.feemanage.service.IBizProjectPayoutDetailService;
import com.feemanage.service.IBizProjectPayoutService;
import com.flowable.domain.vo.task.BpmTaskApproveReqVO;
import com.flowable.service.IFlowTaskService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BizProjectPayoutServiceImpl implements IBizProjectPayoutService {

    @Autowired
    private bizProjectPayoutMapper baseMapper;

    @Autowired
    private IBizProjectPayoutDetailService detailService;

    @Autowired
    private bizProjectPayoutDetailMapper detailsMapper;

    @Autowired
    private ApprovalApi approvalApi; //发起流程

    @Autowired
    private IFlowTaskService flowTaskService;//流程引擎

    private final static String project_Class_xJ="xJProject"; // 校级项目
    private final static String project_Class_yF="yfContract"; // 横向项目
    private final static String project_Class_zX="zXProject"; // 纵向项目
    private  final static  String modelName="经费支出报销";
    /**
     * 查询列表
     * @param pageDomain
     * @param payout
     * @return
     */
    @Override
    public IPage<BizProjectPayoutVo> selectList(PageDomain pageDomain, BizProjectPayout payout) {
        Page<BizProjectPayoutVo> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
        QueryWrapper<BizProjectPayout> wrapper = getQuery(payout);
        String orderByColumn = SqlUtil.escapeOrderBySql(pageDomain.getOrderByColumn());
        boolean isASC = SqlUtil.escapeOrderBySql(pageDomain.getIsAsc()).equalsIgnoreCase("asc");
        if (!StringUtils.isEmpty(orderByColumn))
        {
            wrapper.orderBy(true,isASC,orderByColumn);
        }

        IPage<BizProjectPayoutVo> list = baseMapper.selectPageList(page,wrapper);
        // 获取流程任务列表,Map<instanceId, taskId>
        Map<String, String> instanceTaskMap = approvalApi.getInstanceTaskMap(modelName);
        for (BizProjectPayoutVo u : list.getRecords()) {
            // 判断是否是审核人，并设置taskId
            String processInstanceId = u.getProcessInstanceId();
            if (com.common.utils.StringUtils.isNotEmpty(processInstanceId) && instanceTaskMap.containsKey(processInstanceId)) {
                u.setTaskId(instanceTaskMap.get(processInstanceId));
                u.setIsAuditor(true);
            } else {
                u.setIsAuditor(false);
            }
        }
        return list;
    }


    /**
     * 导出
     * @param payout
     * @return
     */
    @Override
    public List<BizProjectPayoutVo> selectExportList(PageDomain pageDomain, BizProjectPayout payout) {
        QueryWrapper<BizProjectPayout> wrapper = getQuery(payout);
        String orderByColumn = SqlUtil.escapeOrderBySql(pageDomain.getOrderByColumn());
        boolean isASC = SqlUtil.escapeOrderBySql(pageDomain.getIsAsc()).equalsIgnoreCase("asc");
        if (!StringUtils.isEmpty(orderByColumn))
        {
            wrapper.orderBy(true,isASC,orderByColumn);
        }
        return baseMapper.selectPageList(wrapper);
    }

    /**
     * 拼接条件
     * @param payout
     * @return
     */
    public QueryWrapper<BizProjectPayout> getQuery(BizProjectPayout payout){
        Map<String, Object> params = payout.getParams();
        QueryWrapper<BizProjectPayout> wrapper = Wrappers.query();
        wrapper.eq(ObjectUtils.isNotNull(payout.getProjectId()), "p.id", payout.getProjectId())
                .like(StringUtils.isNotBlank(payout.getCwPznm()), "b.cw_pznm", payout.getCwPznm())
                .like(StringUtils.isNotBlank(payout.getProjectName()), "p.name", payout.getProjectName())
                .like(StringUtils.isNotBlank(payout.getNote()), "b.note", payout.getNote())
                .like(StringUtils.isNotBlank(payout.getChargerName()),"p.charger_name",payout.getChargerName())
                .between(ObjectUtils.isNotEmpty(params.get("beginTime"))  && ObjectUtils.isNotEmpty(params.get("endTime")),
                        "b.payout_date", params.get("beginTime"), params.get("endTime"))
                .ge(ObjectUtils.isNotEmpty(params.get("beginTime")) && ObjectUtils.isEmpty(params.get("endTime")),"b.payout_date", params.get("beginTime"))
                .le(ObjectUtils.isEmpty(params.get("beginTime")) && ObjectUtils.isNotEmpty(params.get("endTime")),"b.payout_date", params.get("endTime"))
                .between(ObjectUtils.isNotEmpty(params.get("maxfee")) && ObjectUtils.isNotEmpty(params.get("minfee")),
                        "b.payout_fee", params.get("minfee"), params.get("maxfee"))
                .ge(ObjectUtils.isNotEmpty(params.get("minfee")) && ObjectUtils.isEmpty(params.get("maxfee")),"b.payout_fee", params.get("minfee"))
                .le(ObjectUtils.isNotEmpty(params.get("maxfee")) && ObjectUtils.isEmpty(params.get("minfee")),"b.payout_fee", params.get("maxfee"))
                .between(ObjectUtils.isNotEmpty(params.get("maxprofee")) && ObjectUtils.isNotEmpty(params.get("minprofee")),
                        "p.fee_authorize", SearchUtils.processAmount(params.get("minprofee")), SearchUtils.processAmount(params.get("maxprofee")))
                .ge(ObjectUtils.isNotEmpty(params.get("minprofee")) && ObjectUtils.isEmpty(params.get("maxprofee")),"p.fee_authorize", SearchUtils.processAmount(params.get("minprofee")))
                .le(ObjectUtils.isNotEmpty(params.get("maxprofee")) && ObjectUtils.isEmpty(params.get("minprofee")),"p.fee_authorize", SearchUtils.processAmount(params.get("maxprofee")));

        if(StringUtils.isNotEmpty(payout.getProjectType())){
            List<String> list = Arrays.stream(payout.getProjectType().split(",")).collect(Collectors.toList());
            wrapper.in("p.project_type",list);
        }
        if(StringUtils.isNotEmpty(payout.getUnitId())){
            List<String> list = Arrays.stream(payout.getUnitId().split(",")).collect(Collectors.toList());
            wrapper.in("p.unit_id",list);
        }
        if(StringUtils.isNotEmpty(payout.getProjectClass())){
            List<String> list = Arrays.stream(payout.getProjectClass().split(",")).collect(Collectors.toList());
            wrapper.in("p.project_class",list);
        }

        //当前用户的角色
        String currentRoleKey = CurrentRoleUtils.getCurrentRoleKey();
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        if (("biz_kyry").equals(currentRoleKey)) {//科研人员
            wrapper.eq("p.charger_code",loginUser.getUserRealId());
        }
        if (("biz_kyms").equals(currentRoleKey)) {//科研秘书 查看所属单位下的所有项目
            String units = loginUser.getUnitAdminScopeReal();
            if (StringUtils.isNotEmpty(units)) {
                List<String> unit = Arrays.stream(units.split(",")).collect(Collectors.toList());
                wrapper.in("p.unit_id",unit);
            }
        }

        return wrapper;
    }


    /**
     * 获取预算信息list
     * @param detailsBo
     * @return
     */
    @Override
    public List<BudgetSubjectPayout> getpayoutInfo(PayoutDetailsBo detailsBo){

        QueryWrapper<PayoutDetailsBo> wrapper = Wrappers.query();
        wrapper.eq("f.project_id",detailsBo.getProjectId());

        //只有纵向项目有专项
        if(detailsBo.getProjectClass().equals(project_Class_zX)){
            if(detailsBo.getFeesource().equals("1")){
                wrapper.eq("f.budget_type","liuxiao");
            }else{
                wrapper.eq("f.budget_type","peitao");
            }
        }
        if(detailsBo.getProjectClass().equals(project_Class_yF)){
            wrapper.eq("f.budget_type","yfContract");
        }
        if (detailsBo.getProjectClass().equals(project_Class_xJ)){
            wrapper.eq("f.budget_type","liuxiao");
        }
        wrapper.groupBy("f.SUBJECT_ID,f.SUBJECT_CODE,d.NAME,d1.ID,f.SUBJECT_FEE")
                .orderByAsc("f.SUBJECT_CODE");
        List<BudgetSubjectPayout> subjectList = baseMapper.selectSubjectList(wrapper,detailsBo.getFeesource(),detailsBo.getId());
        List<BudgetSubjectPayout> treeSubjectList = buildTree(null, subjectList);

        return  treeSubjectList;
    }

    public List<BudgetSubjectPayout> buildTree(String parentId, List<BudgetSubjectPayout> treeList) {
        List<BudgetSubjectPayout> list = treeList.stream()
                // 筛选父节点
                .filter(t -> (StringUtils.isEmpty(parentId) && StringUtils.isEmpty(t.getParentCode())) || (StringUtils.isNotEmpty(parentId) && parentId.equals(t.getParentCode())))
                // 递归设置子节点
                .map(item -> {
                    item.setChildren(buildTree(item.getCode(), treeList));
                    return item;
                })
                .collect(Collectors.toList());
        // 递归计算父节点费用
        list.forEach(root -> calculateFee(root));
        return list;
    }

    private static BigDecimal calculateFee(BudgetSubjectPayout node) {
        if (node.getChildren().isEmpty()) {
            return node.getAvailableFee();
        }

        BigDecimal sum = node.getChildren().stream()
                .map(BudgetSubjectPayout::getAvailableFee)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        node.setAvailableFee(sum);
        return sum;
    }

    /**
     * 新增
     * @param payoutBo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String addProOutFee(ProjectPayoutBo payoutBo) {
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        BizProjectPayout payout = new BizProjectPayout();
        BeanUtils.copyProperties(payoutBo,payout);
        payout.setPayoutDate(LocalDateTime.of(payoutBo.getPayoutDate(), LocalTime.MIN));
        //暂存和保存并通过
        if(!payoutBo.getStatus().equalsIgnoreCase("1")){
            payout.setCheckstatus(payoutBo.getStatus());
            payout.setCheckdate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            payout.setChecker(loginUser.getNickName());
            if(payoutBo.getStatus().equalsIgnoreCase("2")){
                payout.setProcessInstanceId("0");//保存并通过
            }
        }
        Boolean flag = baseMapper.insert(payout)>0;
        if(flag){
            List<BizProjectPayoutDetail> detailList = new ArrayList<>();
            List<PayoutDetailsBo> detailsBoList = payoutBo.getPayoutDetails();
            for (PayoutDetailsBo bo:detailsBoList){
                BizProjectPayoutDetail detail = new BizProjectPayoutDetail();
                BeanUtils.copyProperties(bo,detail);
                detail.setProjectPayoutId(payout.getId());
                detail.setProjectId(payout.getProjectId());
                detail.setPayoutDate(payout.getPayoutDate());
                detail.setPayoutPersonName(payout.getPayoutPersonName());
                detailList.add(detail);
            }
            flag = detailService.saveBatch(detailList);
        }
        String msg = flag ? null :"操作失败";
        if(StringUtils.isEmpty(msg)){
            //提交 1
            if(payoutBo.getStatus().equalsIgnoreCase("1")){
                String processInstanceId = approvalApi.businessEntryApproval(payout.getId(), modelName);
                msg = StringUtils.isEmpty(processInstanceId)? BizProcessMessages.SAVE_PARTIAL_SUCCESS:null;
            }
        }
        return msg;
    }

    /**
     * 编辑
     * @param payoutBo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String editProOutFee(ProjectPayoutBo payoutBo) {
        SysUser loginUser = SecurityUtils.getLoginUser().getUser();
        BizProjectPayout payout = new BizProjectPayout();
        BeanUtils.copyProperties(payoutBo,payout);
        //暂存和保存并通过
        if(!payoutBo.getStatus().equalsIgnoreCase("1")){
            //数据状态不为审核中,不更新数据状态
            if(!payoutBo.getCheckstatus().equalsIgnoreCase("1")) {
                payout.setCheckstatus(payoutBo.getStatus());
                payout.setCheckdate(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                payout.setChecker(loginUser.getNickName());
                if (payoutBo.getStatus().equalsIgnoreCase("2")) {
                    payout.setProcessInstanceId("0");//数据状态为暂存和不通过，点击保存并通过
                }
            }
        }
        Boolean flag = baseMapper.updateById(payout) >0;
        if(flag){
            List<BizProjectPayoutDetail> detailList = new ArrayList<>();
            List<PayoutDetailsBo> list = payoutBo.getPayoutDetails();
            for (PayoutDetailsBo bo:list){
                BizProjectPayoutDetail detail = new BizProjectPayoutDetail();
                BeanUtils.copyProperties(bo,detail);
                //如果id为空，插入
                if(StringUtils.isEmpty(detail.getId())){
                    detail.setProjectPayoutId(payout.getId());
                    detail.setProjectId(payout.getProjectId());
                    detail.setPayoutDate(payout.getPayoutDate());
                    detail.setPayoutPersonName(payout.getPayoutPersonName());
                }
                detailList.add(detail);
            }
            flag = detailService.saveOrUpdateBatch(detailList);
        }
        String msg = flag ? null :"操作失败";
        if(StringUtils.isEmpty(msg)){
            //按钮状态为提交 1
            if(payoutBo.getStatus().equalsIgnoreCase("1")){
                String processInstanceId = approvalApi.businessEntryApproval(payout.getId(), modelName);
                msg = StringUtils.isEmpty(processInstanceId)? BizProcessMessages.SAVE_PARTIAL_SUCCESS:null;
            }
            //按钮状态为保存并通过2，数据状态为审核中，当前流程节点通过
            if(payoutBo.getStatus().equalsIgnoreCase("2") && payoutBo.getCheckstatus().equalsIgnoreCase("1")){
                BpmTaskApproveReqVO bta = new BpmTaskApproveReqVO();
                bta.setId(payoutBo.getTaskId());
                bta.setReason(SecurityUtils.getNickName() + "保存并通过");
                flowTaskService.approveTask(SecurityUtils.getUserId(), bta);
            }
        }
        return msg;
    }


    /**
     * 删除
     * @param ids
     * @param isValid
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean delProOutFee(Collection<String> ids, Boolean isValid){

        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        //先删从表，再删主表
        Boolean flag = detailsMapper.delete(new QueryWrapper<BizProjectPayoutDetail>().in("project_payout_id",ids))>0;
        Boolean flagMain = baseMapper.deleteBatchIds(ids) >0;
        return flag && flagMain;
    }


    /**
     * 获取详情数据
     * @param payoutBo
     * @return
     */
    public ProjectPayoutVo getEditInfo(ProjectPayoutBo payoutBo){
        ProjectPayoutVo vo = baseMapper.selectListOne(new QueryWrapper<BizProjectPayout>().eq(StringUtils.isNotEmpty(payoutBo.getId()),"b.ID",payoutBo.getId()));
        if(vo != null && ObjectUtils.isNotEmpty(vo.getPayoutDetails())){
            for (PayoutDetailsBo detail : vo.getPayoutDetails()) {
                QueryWrapper<PayoutDetailsBo> wrapper = Wrappers.query();
                wrapper.eq("f.project_id",vo.getProjectId())
                        .eq("f.SUBJECT_ID",detail.getBudgetSubjectId());
                //只有纵向项目有专
                if(vo.getProjectClass().equals(project_Class_zX)){
                    if(detail.getFeesource().equals("1")){
                        wrapper.eq("f.budget_type","liuxiao");
                    }else{
                        wrapper.eq("f.budget_type","peitao");
                    }
                }
                if(vo.getProjectClass().equals(project_Class_yF)){
                    wrapper.eq("f.budget_type","yfContract");
                }
                if (vo.getProjectClass().equals(project_Class_xJ)){
                    wrapper.eq("f.budget_type","liuxiao");
                }
                wrapper.groupBy("f.SUBJECT_ID,d.NAME,d1.ID,f.SUBJECT_FEE").last("limit 1");

                BudgetSubjectPayout payout = baseMapper.selectSubjectList(wrapper,detail.getFeesource(),"",payoutBo.getId());
                if(ObjectUtils.isNotEmpty(payout)){
                    detail.setAvailableFee(payout.getAvailableFee());
                }
            }
        }
        return  vo;
    }
}
